package com.sina.medical.service;


import com.sina.medical.core.base.BaseCriteria;
import com.sina.medical.core.dao.BaseDao;
import com.sina.medical.core.dao.BaseService;
import com.sina.medical.core.exception.SinaCustomException;
import org.hibernate.exception.DataException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import static com.sina.medical.service.ServiceConstant.MEDICAL_TX;
import static org.springframework.transaction.annotation.Isolation.READ_COMMITTED;
import static org.springframework.transaction.annotation.Isolation.REPEATABLE_READ;

/**
 */
@Service("medicalceDataSourceService")
public class MedicalDataSourceService implements BaseService {

    protected final Logger LOG = LoggerFactory.getLogger(this.getClass());

    protected BaseDao baseDao;

    @Transactional(value = MEDICAL_TX, isolation = READ_COMMITTED)
    @Override
    public Serializable create(Object entity) {
        return baseDao.save(entity);
    }

    @Transactional(value = MEDICAL_TX, isolation = REPEATABLE_READ)
    @Override
    public void createOrUpdate(Object entity) {
        baseDao.saveOrUpdate(entity);
    }

    @Transactional(value = MEDICAL_TX, isolation = REPEATABLE_READ)
    @Override
    public void update(Object entity) {
        baseDao.update(entity);
    }

    @Transactional(value = MEDICAL_TX, isolation = READ_COMMITTED, readOnly = true)
    @Override
    public <T> T get(Class<T> entityClass, Serializable id) {
        return baseDao.get(entityClass, id);
    }

    @Transactional(value = MEDICAL_TX, isolation = REPEATABLE_READ)
    @Override
    public void delete(Object entity) {
        baseDao.delete(entity);
    }

    @Transactional(value = MEDICAL_TX, isolation = READ_COMMITTED, readOnly = true)
    @Override
    public <T> List<T> list(Class<T> clazz, int page, int max) {
        int first = (page - 1) * max;
        return baseDao.listWithCommon(clazz, first, max);
    }

    @Transactional(value = MEDICAL_TX, isolation = READ_COMMITTED, readOnly = true)
    @Override
    public <T> List<T> list(Class<T> clazz, BaseCriteria criteria, long[] count) {
        if (count != null && count.length > 0) {
            count[0] = baseDao.count(clazz, criteria);
        }
        return baseDao.list(clazz, criteria);
    }

    @Transactional(value = MEDICAL_TX, isolation = READ_COMMITTED)
    @Override
    public <T> boolean delete(Class<T> entityClass, Serializable id) {
        return baseDao.deleteOne(entityClass, id);
    }

    @Transactional(value = MEDICAL_TX, isolation = REPEATABLE_READ)
    @Override
    public void delete(Collection entities) {
        int count = 0;
        for (Object entity : entities) {
            baseDao.delete(entity);
            count++;
            if (count % BaseDao.BATCH == 0) {
                baseDao.flush();
                baseDao.clear();
            }
        }
    }

    @Transactional(value = MEDICAL_TX, isolation = READ_COMMITTED, readOnly = true)
    @Override
    public <T> T getWithException(Class<T> entityClass, Serializable id) throws DataException {
        return baseDao.getWithException(entityClass, id);
    }

    @Transactional(value = MEDICAL_TX, isolation = READ_COMMITTED, readOnly = true)
    @Override
    public boolean isExists(Class<?> entityClass, Serializable id) {
        return baseDao.isExists(entityClass, id);
    }

    @Transactional(value = MEDICAL_TX, isolation = READ_COMMITTED, readOnly = true)
    @Override
    public <T> boolean isExistsByUnique(Class<T> entityClass, String propName, Serializable uniqueProp) throws SinaCustomException {
        return baseDao.isExistsByUnique(entityClass, propName, uniqueProp);
    }

    @Transactional(value = MEDICAL_TX, isolation = READ_COMMITTED, readOnly = true)
    @Override
    public void isExistsWithException(Class<?> entityClass, Serializable id)
            throws SinaCustomException {
        baseDao.isExistsWithException(entityClass, id);
    }

    @Autowired
    public MedicalDataSourceService setBaseDao(@Qualifier("medicalDataSourceDao") BaseDao baseDao) {
        this.baseDao = baseDao;
        return this;
    }
}
